네이버 영화 20만개의 리뷰를 모은 데이터셋을 이용한다.
15만개는 훈련 데이터셋으로 5만개는 테스트 데이터 셋으로 이용
/Users/csian/CP/git_hub/080223/Ch08
ratings_test.txt
ratings_train.txt
리뷰의 길이는 140을 넘지 않으며, 부정 리뷰는 1-4까지의 점수를 매긴 리뷰
긍정 리뷰는 6-10까지 점수를 매긴 리뷰이다.
훈련 데이터셋과 테스트 데이터셋의 부정과 긍정 리뷰는 약 50%씩 구성되어 있다.
한글은 영어와 달리 조사와 어미가 발달해 있다.
BoW나 어간 추출보다 표제어 추출 방식이 적합하다.
표제어 추출 방식의 작업을 형태소 분석이라고 한다.
형태소 분리를 위해서 konlpy와 soynlp를 이용한다.
pip3 install konlpy soynlp
train data files
import konlpy
import pandas as pd
import numpy as np
df_train=pd.read_csv('/Users/csian/Desktop/CP/git_hub/080223/Ch08/ratings_train.txt', delimiter='\t', keep_default_na=False)
기본적으로 pd.read_csv는 콤마(‘ , ‘)를 필드를 구분하기 때문에 delimiter를 \t(tab)으로 변경 시켜준다.
id document label
0 9976970 아 더빙.. 진짜 짜증나네요 목소리 0
1 3819312 흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나 1
2 10265843 너무재밓었다그래서보는것을추천한다 0
3 9045019 교도소 이야기구먼 ..솔직히 재미는 없다..평점 조정 0
4 6483659 사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 ... 1
X_train=df_train['document'].values
y_train=df_train['label'].values
test data files
df_test=pd.read_csv('/Users/csian/Desktop/CP/git_hub/080223/CH08/ratings_test.txt', delimiter='\t', keep_default_na=False)
X_test=df_test['document'].values
y_test=df_test['label'].values
print(len(X_train), np.bincount(y_train))
print(len(X_test), np.bincount(y_test))
150000 [75173 74827]
50000 [24827 25173]
konlpy Okt(open-korean-text) 한국어 처리기
from konlpy.tag import Okt
okt=Okt()
print(X_train[4])
print(okt.morphs(X_train[4]))
사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 던스트가 너무나도 이뻐보였다
['사이', '몬페', '그', '의', '익살스런', '연기', '가', '돋보였던', '영화', '!', '스파이더맨', '에서', '늙어', '보이기만', '했던', '커스틴', '던스트', '가', '너무나도', '이뻐', '보였다']
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf=TfidfVectorizer(ngram_range=(1, 2), min_df=3, max_df=0.9, tokenizer=okt.morphs, token_pattern=None)
tfidf.fit(X_train)
X_train_okt=tfidf.transform(X_train)
X_test_okt=tfidf.transform(X_test)
SGDClassifier 클래스를 이용한 감성 분류
from sklearn.model_selection import RandomizedSearchCV
from sklearn.linear_model import SGDClassifier
from sklearn.utils.fixes import loguniform
sgd=SGDClassifier(loss='log', random_state=1)
param_dist={'alpha':loguniform(0.0001, 100.0)}
rsv_okt=RandomizedSearchCV(estimator=sgd, param_distributions=param_dist, n_iter=50, random_state=1, verbose=1, n_jobs=-1)
rsv_okt.fit(X_train_okt, y_train)
print(rsv_okt.best_score_)
print(rsv_okt.best_params_)
0.8251533333333334
{'alpha': 0.0001001581395585897}
rsv_okt.score(X_test_okt, y_test)
soynlp LTokenizer
soynlp 한국어 형태소 분리 패키지는 세 개의 토큰화 클래스를 제공한다.
LTokenizer, MaxScoreTokenizer, RegexTokenizer이다.
from soynlp.tokenizer import LTokenizer
lto=LTokenizer()
print(lto.tokenize(X_train[4]))
['사이몬페그의', '익살스런', '연기가', '돋보였던', '영화!스파이더맨에서', '늙어보이기만', '했던', '커스틴', '던스트가', '너무나도', '이뻐보였다']
soynlp는 말뭉치의 통계 데이터를 기반으로 동작하기 때문에 기본 LTokenizer 객체로는 공백으로만 토큰화를 수행한다.
LTokenizer에 필요한 통계 데이터를 생성하기 위해 WordExtractor를 사용한다.
from soynlp.word import WordExtractor
word_ext=WordExtractor()
word_ext.train(X_train)
training ... (100000 in 150000 sents) use memory 4.896 Gbscores=word_ext.word_scores()
training was done. used memory 5.925 Gb
scores=word_ext.word_scores()
all cohesion probabilities was computed. # words = 85683
all branching entropies was computed # words = 101540
all accessor variety was computed # words = 101540
soynlp 깃허브 튜토리얼을 따라 결합점수(cohesion_forward)와 브랜칭 엔트로피(right_branching_entropy)에
지수를 취한 값에 곱해 최종 점수를 만든다.
import math
score_dict={key:scores[key].cohesion_forward*math.exp(scores[key].right_branching_entropy)for key in scores}
lto=LTokenizer(scores=score_dict)
print(lto.tokenize(X_train[4]))
['사이', '몬페그의', '익살스', '런', '연기', '가', '돋보', '였던', '영화', '!스파이더맨에서', '늙어', '보이기만', '했던', '커스틴', '던스트가', '너무', '나도', '이뻐', '보였다']
단어 점수를 활용하여 토큰 추출이 이루어졌다.
tfidf=TfidfVectorizer(ngram_range=(1, 2), min_df=3, max_df=0.9, tokenizer=lto.tokenize, token_pattern=None)
tfidf.fit(X_train)
X_train_soy=tfidf.transform(X_train)
X_test_soy=tfidf.transform(X_test)
SGDClassifier 객체와 매개변수 분포를 지정하고 하이퍼파라미터 탐색을 수행
rsv_soy=RandomizedSearchCV(estimator=sgd, param_distributions=param_dist, n_iter=50, random_state=1, verbose=1, n_jobs=-1)
rsv_soy.fit(X_train_soy, y_train)
print(rsv_soy.best_score_)
print(rsv_soy.best_params_)
0.8141066666666665
{'alpha': 0.0001001581395585897}
rsv_soy.score(X_test_soy, y_test)